# app/main.py

import os
from pathlib import Path
import logging
from fastapi import FastAPI, Request, HTTPException, status, Depends
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from sqlalchemy.orm import Session
from .config import config  # 修改这里
from .database import SessionLocal, engine, Base
from . import models, schemas, crud
from .utils import send_email
from datetime import datetime
import re

# 创建数据库表（首次运行时）
Base.metadata.create_all(bind=engine)

app = FastAPI()

# 定义基础目录
BASE_DIR = Path(__file__).resolve().parent

# 挂载静态文件
static_dir = BASE_DIR / "static"
if not static_dir.exists():
    raise RuntimeError(f"Static directory not found at {static_dir}")
app.mount("/static", StaticFiles(directory=static_dir), name="static")

# 初始化模板
templates = Jinja2Templates(directory=BASE_DIR / "templates")

# 设置日志记录
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
logging.basicConfig(
    filename=config.LOG_FILE,
    level=logging.INFO,
    format='[%(asctime)s] %(levelname)s: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

# 依赖项获取数据库会话
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# DCO 正则表达式
DCO_REGEX = re.compile(r'^Signed-off-by:\s+([^<]+)<([^>]+)>$', re.IGNORECASE)

@app.post("/webhook", response_class=JSONResponse)
async def webhook(request: Request, db: Session = Depends(get_db)):
    headers = request.headers
    signature = headers.get('X-Gitlab-Token', '')

    # 验证签名
    if config.WEBHOOK_SECRET and signature != config.WEBHOOK_SECRET:
        logger.warning("Webhook 签名验证失败。")
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Unauthorized")

    event_type = headers.get('X-Gitlab-Event', '')
    logger.info(f"处理事件类型: {event_type}")

    if event_type.lower() != 'push hook':
        logger.info("事件类型不处理。")
        return JSONResponse(status_code=200, content={"message": "Event not handled"})

    data = await request.json()
    if not data:
        logger.error("解析 Webhook 负载失败：无有效 JSON。")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid payload")

    logger.debug(f"Webhook Payload: {data}")

    # 获取推送信息
    repository = data.get('project', {})
    owner = repository.get('namespace', '')
    repo = repository.get('name', '')
    commits = data.get('commits', [])
    pusher = data.get('user_username', '')
    ref = data.get('ref', '')
    before = data.get('before', '')
    after = data.get('after', '')

    if not owner or not repo or not commits:
        logger.error("缺少必要的仓库或提交信息。")
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Missing information")

    logger.info(f"处理仓库: {owner}/{repo}, Pusher: {pusher}, Ref: {ref}")

    # 创建 WebhookEvent
    event_data = schemas.WebhookEventSchema(
        repository_name=repo,
        repository_owner=owner,
        pusher=pusher,
        ref=ref,
        before_sha=before,
        after_sha=after,
        received_at=datetime.utcnow(),
        invalid_commits=[]
    )
    db_event = crud.create_webhook_event(db, event=event_data)
    logger.debug(f"插入 webhook_events ID: {db_event.id}")

    invalid_commits = []

    for commit in commits:
        message = commit.get('message', '')
        sha = commit.get('id', '')
        author = commit.get('author', {}).get('name', '')
        url = commit.get('url', '')

        logger.debug(f"验证提交 {sha} 的 DCO 签名。")

        has_dco = False
        lines = message.split('\n')
        for line in lines:
            if DCO_REGEX.match(line.strip()):
                has_dco = True
                logger.debug("找到有效的 DCO 签名。")
                break

        if not has_dco:
            logger.info(f"提交 {sha} 由 {author} 创建，未通过 DCO 验证。")
            invalid_commit_data = schemas.InvalidCommitSchema(
                sha=sha,
                author=author,
                message=message,
                url=url,
                detected_at=datetime.utcnow()
            )
            db_commit = crud.create_invalid_commit(db, commit=invalid_commit_data, event_id=db_event.id)
            invalid_commits.append(db_commit)

    if invalid_commits:
        subject = config.EMAIL_SUBJECT
        body = config.EMAIL_BODY_TEMPLATE

        for commit in invalid_commits:
            body += f"- **Commit SHA**: {commit.sha}\n"
            body += f"  - **作者**: {commit.author}\n"
            body += f"  - **消息**: {commit.message}\n"
            body += f"  - **链接**: {commit.url}\n\n"

        # 发送邮件通知
        send_email(subject, body, config.EMAIL_RECIPIENT)

        logger.info(f"发现 {len(invalid_commits)} 个未通过 DCO 验证的提交，已发送邮件通知。")
    else:
        logger.info("所有提交均通过 DCO 验证。")

    return JSONResponse(status_code=200, content={"message": "Processed"})

@app.get("/", response_class=HTMLResponse)
async def index(request: Request, db: Session = Depends(get_db)):
    query = request.query_params.get('query', '')
    if query:
        filters = {
            'repository': query,
            'owner': query,
            'pusher': query,
            'invalid_commits': ''
        }
        events = crud.get_events(db, filters)
    else:
        events = crud.get_events(db, {})
    return templates.TemplateResponse("index.html", {"request": request, "events": events})

@app.get("/view_events", response_class=HTMLResponse)
async def view_events(request: Request, 
                      repository: str = None,
                      owner: str = None,
                      pusher: str = None,
                      date_from: str = None,
                      date_to: str = None,
                      invalid_commits: str = None,
                      db: Session = Depends(get_db)):
    filters = {}
    if repository:
        filters['repository'] = repository
    if owner:
        filters['owner'] = owner
    if pusher:
        filters['pusher'] = pusher
    if date_from:
        try:
            filters['date_from'] = datetime.strptime(date_from, '%Y-%m-%d')
        except ValueError:
            logger.warning(f"日期格式错误: {date_from}")
    if date_to:
        try:
            filters['date_to'] = datetime.strptime(date_to, '%Y-%m-%d')
        except ValueError:
            logger.warning(f"日期格式错误: {date_to}")
    if invalid_commits in ['yes', 'no']:
        filters['invalid_commits'] = invalid_commits

    events = crud.get_events(db, filters)
    logger.info(f"展示事件数量: {len(events)}")
    return templates.TemplateResponse("view_events.html", {"request": request, "events": events, "filters": filters})

@app.get("/env_test", response_class=JSONResponse)
async def env_test():
    return {
        "DATABASE_URI": config.DATABASE_URL,
        "WEBHOOK_SECRET": config.WEBHOOK_SECRET,
        "EMAIL_RECIPIENT": config.EMAIL_RECIPIENT
    }

@app.exception_handler(404)
async def not_found(request: Request, exc: HTTPException):
    logger.warning(f"页面未找到: {request.url}")
    return templates.TemplateResponse("404.html", {"request": request}, status_code=404)

@app.exception_handler(500)
async def internal_error(request: Request, exc: HTTPException):
    logger.error(f"内部服务器错误: {exc}")
    return templates.TemplateResponse("500.html", {"request": request}, status_code=500)
